package com.ztesoft.zsmart.zcm.monitor.utils;

import com.ztesoft.zsmart.core.exception.BaseAppException;
import com.ztesoft.zsmart.core.log.ZSmartLogger;
import com.ztesoft.zsmart.core.util.JsonUtil;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class HttpsUtil {
    private static ZSmartLogger logger = ZSmartLogger.getLogger(HttpsUtil.class);

    private static SSLContextBuilder builder;

    private static SSLConnectionSocketFactory sslConnectionSocketFactory;

    private static Registry registry;

    private static PoolingHttpClientConnectionManager connectionManager;

    private static RequestConfig defaultRequestConfig;
    static {
        builder = new SSLContextBuilder();
        try {
            builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
            SSLContext ctx = null;
            try {
                ctx = SSLContext.getInstance("TLS");
                ctx.init(new KeyManager[0], new TrustManager[] {
                    new DefaultTrustManager()
                }, new SecureRandom());
            }
            catch (Exception e) {
                throw new IOException(e);
            }
            sslConnectionSocketFactory = new SSLConnectionSocketFactory(ctx);
            registry = RegistryBuilder.create().register("https", sslConnectionSocketFactory).build();
            connectionManager = new PoolingHttpClientConnectionManager(registry);
            connectionManager.setMaxTotal(100);
            defaultRequestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000).setStaleConnectionCheckEnabled(true).build();
        }
        catch (Exception e) {
            logger.error(e);
        }

    }

    public static String post(String url, String json) {
        // https 请求忽略证书
        String param = null;
        try {
            param = JsonUtil.object2Json(json);
        }
        catch (BaseAppException e) {
            logger.error(e);
        }
        return postHttps(url, param);
    }

    public static String postObject(String url, Object obj) {
        // https 请求忽略证书
        String param = null;
        try {
            param = JsonUtil.object2Json(obj);
        }
        catch (BaseAppException e) {
            logger.error(e);
        }
        return postHttps(url, param);
    }

    private static String postHttps(String url, String param) {
        CloseableHttpClient httpClient = null;
        HttpPost method = null;
        try {
            httpClient = getIgnoeSSLClient();
            // 将使用户信息同步到第三方系统中
            // 发送post请求
            method = new HttpPost(url);
            // 准备json数据发送参数
            // 处理中文乱码问题
            StringEntity entity = new StringEntity(param, "utf-8");
            entity.setContentType("application/json");
            method.setEntity(entity);
            // 发送请求
            logger.info("https: " + method);
            CloseableHttpResponse execute = httpClient.execute(method);
            return EntityUtils.toString(execute.getEntity(), "UTF-8");
        }
        catch (Exception e) {
            logger.error(e);
        }
        finally {
            if (method != null) {
                method.releaseConnection();
            }
        }
        return "failed";
    }

    private static CloseableHttpClient getIgnoeSSLClient() {
        CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig)
            .setSSLHostnameVerifier((hostName, sslSession) -> {
                return true;
            }).setConnectionManager(connectionManager).setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
        return client;
    }

    private static class DefaultTrustManager implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }
    }
}
